package graphic.tests;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

/**
 * 
 * @author Jan
 *
 */
public class RenderTest01 extends Canvas implements Runnable {


	private static final long serialVersionUID = -2937001437943245458L;
	
	public static final int WIDTH = 1280;
	public static final int HEIGHT = 720;//WIDTH / 16 * 9;
	
	private boolean isRunning = false;
	private int ticksCount = 0;
	private Thread thread;
	
	private BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);
	private int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
	
	
	public RenderTest01() {
		super();
		Dimension dimension = new Dimension(WIDTH, HEIGHT);
		setPreferredSize(dimension);
	}
	
	/**
	 * Metodo per l'avvio del Thread grafico.
	 */
	public synchronized void start(){
		isRunning = true;
		thread = new Thread(this, "Test Thread");
		thread.start();
	}
	
	/**
	 * Metodo per lo stop del Thread grafico.
	 */
	public synchronized void stop(){
		isRunning = false;
		try {
			thread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void run() {
		//Per limitare gli aggiornamenti ( tick ) e renderizzazione
		
		//Per una buona precisione vengono usati i nanosecondi.
		long lastTime = System.nanoTime();		
		double nsPerTick = 1000000000D/60; 		// FPS
		
		//Aggiornamenti renderizzati.
		int ticks = 0;
		//Frame renderizzati.
		int frames = 0;	
		
		long lastTimer = System.currentTimeMillis();
		
		//Tempo in ns trascorso tra un aggiornamento e l'altro.
		//Ovviamente lo si vuole minimizzare
		double delta = 0;						
		
		while(isRunning){
			long now = System.nanoTime();
			delta += ( now - lastTime )/nsPerTick;
			lastTime = now;
			
			//boolean needRender = false;		//Attiva il blocco.
			boolean needRender = true;
			
			while( delta >= 1){					//Si resta nel loop in modo da limitare gli aggiornamenti a video
				ticks++;
				tick();
				delta -= 1;
				needRender = true;
			}
			
			try {
				Thread.sleep(2);				//In mancanza del blocco, introduce un delay per minimizzare il carico.
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			if(needRender){
				frames++;
				render();
			}
			
			
			//Dopo ogni secondo vengono resettate le variabili.
			//L'obbiettivo e' avere circa 60FPS
			if( (System.currentTimeMillis() - lastTimer) >= 1000 ){
				lastTimer += 1000;
				//Togliere il commento per visualizzare quante renderizzazioni vengono effettuate ogni secondo.
				System.out.println( frames+","+ticks );
				frames = 0;
				ticks = 0;
			}
		}
	}
	
	/**
	 * Metodo per l'aggiornamento dell'immagine da renderizzare.
	 */
	public void tick(){
		ticksCount++;
		//Test sulle modifiche dei pixel.
		for (int i = 0; i < pixels.length; i++) {
			pixels[i] =i*ticksCount;
		}
	}
	
	/**
	 * Metodo per la renderizzazione dei frame, usando l'immagine aggiornata con tick.
	 */
	public void render(){
		BufferStrategy buffer = getBufferStrategy();
		if(buffer == null){
			createBufferStrategy(3);
			return;
		}
		
		
		Graphics g = buffer.getDrawGraphics();
		g.drawImage(img, 0, 0, getWidth(), getHeight(),null);
		
		
		//Liberazione delle risorse grafiche.
		g.dispose();
		//Bisualizzazione contenuto buffer.
		buffer.show();
	}
	

	//si limita ad aprire il frame e avviare il renderizzatore.
	public static void main(String[] args) {
		RenderTest01 game = new RenderTest01();
		JFrame frame = new JFrame();
		frame.add(game);
		frame.pack();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		game.start();
	}
}
